home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Utilities / Workspace / Background3.2 / Source / background / Background.m < prev    next >
Text File  |  1995-06-12  |  11KB  |  491 lines

  1. //
  2. #import <math.h>
  3. #include <sys/stat.h>
  4.  
  5. #import "Background.h"
  6.  
  7. #import <dpsclient/wraps.h>
  8. #import <appkit/Application.h>
  9. #import <objc/hashtable.h>
  10. #import <defaults/defaults.h>
  11. #import "PSsplat.h"
  12. #import <appkit/OpenPanel.h>
  13. #import <appkit/Control.h>
  14. #import <appkit/Menu.h>
  15. #import <appkit/MenuCell.h>
  16. #import <appkit/Matrix.h>
  17. #import <appkit/nextstd.h>
  18.  
  19. #define PSsplat( r, p)    _PSsplat( (r)->origin.x, (r)->origin.y, \
  20.         (r)->size.width, (r)->size.height, (p)->x, (p)->y)
  21.  
  22. //
  23. @implementation Background:View
  24. //
  25. //
  26.  void handler(DPSTimedEntry teNumber, double now, id background)
  27. {
  28.     [background next:nil];
  29. }
  30.  
  31. - initFrame:(const NXRect *)frameRect
  32. {
  33.     char *d,*f;
  34.     int len;
  35.     
  36.     [super initFrame:frameRect];
  37.     imageNames = NULL;
  38.     imageTimes = NULL;
  39.     images = NULL;
  40.     imageCount = 0;
  41.     max = 0;
  42.     current = 0;
  43.     d = getenv("HOME"); if (!d) d="";
  44.     f = ".background";
  45.     len = strlen(d) + 1 + strlen(f) + 1;
  46.     defaultfile = NX_ZONEMALLOC([self zone], defaultfile, char, len);
  47.     strcpy(defaultfile, d);
  48.     strcat(defaultfile,"/");
  49.     strcat(defaultfile,f);
  50.     timer = NULL;
  51.     repeat = 600;
  52.     permanent = NO;
  53.     updateMenu = YES;
  54.     return self;
  55. }
  56.  
  57.  
  58.  
  59. - reset
  60. {
  61.     int i;
  62.   
  63.     for (i=0; i<imageCount; i++) {
  64.     NXZoneFree([self zone], imageNames[i]);
  65.     if(images[i]) [images[i] free];
  66.     }
  67.     if (imageCount) {
  68.         NXZoneFree([self zone], imageNames);
  69.         NXZoneFree([self zone], imageTimes);
  70.         NXZoneFree([self zone], images);
  71.     }
  72.     imageCount=0;
  73.     current=0;
  74.     return self;
  75. }
  76.  
  77. - free
  78. {
  79.     [self reset];
  80.     if (timer) DPSRemoveTimedEntry(timer);
  81.     return [super free];
  82. }
  83.  
  84. //
  85. - loadImageNamed:(const char *)aName
  86. {
  87.  //    printf("Loading %s.\n", aName);
  88.     if ([self getImage:aName]<0) return nil;
  89.     return self;
  90. }
  91.  
  92. - setImageNamed:(const char *)aName
  93. {
  94.     int i;
  95.     
  96.     i = [self getImage:aName];
  97.     if (i>=0) [self setImage:i]; else return nil;
  98.     return self;
  99. }
  100.  
  101. - setRepeatValue:(float)r
  102. {
  103.     char str[7];
  104.     
  105.     repeat = r;
  106.     if (timer) DPSRemoveTimedEntry(timer);
  107.     if (repeat<1) {
  108.         strcpy(str,"off");
  109.     timer=NULL;
  110.     } else {
  111.         if (r<60) sprintf(str,"%2ds",(int)r);
  112.     else if (r<3600) sprintf(str,"%2dmin",(int)(r/60));
  113.     else sprintf(str,"%2dh",(int)(r/3600));
  114.     timer = DPSAddTimedEntry(repeat, 
  115.         (DPSTimedEntryProc)handler, self, NX_BASETHRESHOLD);
  116.     }
  117.     [repeatText setStringValue:str];
  118.     [repeatSlider setFloatValue:log(r+1)/12];
  119.  //    printf("Setting repeat to %s.\n", str);
  120.     [self writeDefault];
  121.     return self;
  122. }
  123.  
  124. - setRepeatText:aText
  125. {
  126.     repeatText = aText;
  127.     return self;
  128. }
  129.  
  130. - setRepeatSlider:aSlider
  131. {
  132.     repeatSlider = aSlider;
  133.     return self;
  134. }
  135.  
  136. - setPermanent:(BOOL)flag
  137. {
  138.     permanent = flag;
  139.     return self;
  140. }
  141. //
  142. //    target/action
  143. //
  144. - open:sender
  145. {
  146.     OpenPanel *op=[OpenPanel new];
  147.     char *types[]={ "tiff", "eps", NULL};
  148.     char *directory, *filename, *fn;
  149.     const char *d;
  150.     const char * const *files;
  151.     int l, len, ind;
  152.     
  153.     if( !imageCount)
  154.     {
  155.     directory=getenv( "HOME");
  156.     if( !directory)    directory="/";
  157.     filename=NXCopyStringBufferFromZone("", [self zone]);
  158.     } else {
  159.         fn=NXCopyStringBufferFromZone(imageNames[current], [self zone]);
  160.     if (filename=rindex(fn, '/')) *filename++='\0', directory=fn;
  161.     else
  162.     {
  163.         filename=imageNames[current];
  164.         directory=getenv( "HOME");
  165.         if( !directory) directory="/";
  166.     }
  167.     }
  168.     ind = current;
  169.     [op allowMultipleFiles:YES];
  170.     if( [op runModalForDirectory:directory file:filename types:types]) {
  171.         len = 0;
  172.     for (files=[op filenames]; *files; files++) if ((l=strlen(*files))>len) len=l;
  173.     len += strlen(d=[op directory])+2;
  174.     NX_ZONEMALLOC([self zone], fn, char, len);
  175.     strcpy(fn,d);
  176.     strcat(fn,"/");
  177.     filename=rindex(fn, '/')+1;
  178.     for (files=[op filenames]; *files; files++) {
  179.         strcpy(filename,*files);
  180.         if ((l=[self getImage:fn])>0) ind = l;
  181.     }
  182.     }
  183.     [self setImage:ind];
  184.     [self writeDefault];
  185.     return self;
  186. }
  187.  
  188. - next:sender
  189. {
  190.     if (++current>=imageCount) current=0;
  191.     [self setImage:current];
  192.     return self;
  193. }
  194.  
  195. - resize:sender
  196. {
  197.     char *p;
  198.  
  199.     p = imageNames[current];
  200.     if (p[0]=='*') {
  201.     NX_ZONEMALLOC([self zone], imageNames[current], char, strlen(p));
  202.     strcpy(imageNames[current], p+1);
  203.     NXZoneFree([self zone], p);
  204.     [images[current] free];
  205.     images[current]=nil;
  206.     } else {
  207.     NX_ZONEMALLOC([self zone], imageNames[current], char, strlen(p)+2);
  208.     strcpy(imageNames[current],"*");
  209.     strcat(imageNames[current],p);
  210.     NXZoneFree([self zone], p);
  211.     }
  212.     [self resizeImage:current];
  213.     [self setImage:current];
  214.     [self writeDefault];
  215.     return self;
  216. }
  217.  
  218. - previous:sender
  219. {
  220.     if (--current<0) current=imageCount-1;
  221.     [self setImage:current];
  222.     return self;
  223. }
  224.  
  225. - redraw:sender
  226. {
  227.     [self display];
  228.     return self;
  229. }
  230. - select:sender
  231. {
  232.     sender = [sender selectedCell];
  233.     updateMenu=NO;
  234.     [self setImageNamed:[sender title]];
  235.     updateMenu=YES;
  236.     return self;
  237. }
  238. - toFront:sender
  239. {
  240.     PSsetwindowlevel( NX_DOCKLEVEL+1, [window windowNum]);
  241.     [window orderFront:sender];
  242.     [window addToEventMask:NX_MOUSEDOWNMASK];
  243.     return self;
  244. }
  245. - toTop:sender
  246. {
  247.     int i;
  248.     char *n;
  249.     time_t t;
  250.     id img;
  251.     
  252.     n = imageNames[current];
  253.     t = imageTimes[current];
  254.     img = images[current];
  255.     for (i=current; i>0; i--) {
  256.         imageNames[i] = imageNames[i-1];
  257.         imageTimes[i] = imageTimes[i-1];
  258.         images[i] = images[i-1];
  259.     }
  260.     imageNames[0] = n;
  261.     imageTimes[0] = t;
  262.     images[0] = img;
  263.     current = 0;
  264.     [self setImage:current];
  265.     [self writeDefault];
  266.     return self;
  267. }
  268.  
  269. - delete:sender
  270. {
  271.     int i;
  272.     
  273.     for (i=current; i<imageCount; i++) {
  274.         imageNames[i] = imageNames[i+1];
  275.         imageTimes[i] = imageTimes[i+1];
  276.         images[i] = images[i+1];
  277.     }
  278.     imageCount--;
  279.     if (current>=imageCount && current>0) current--;
  280.     [self setImage:current];
  281.     [self writeDefault];
  282.     return self;
  283. }
  284.  
  285. - deleteAll:sender
  286. {
  287.     [self reset];
  288.     [self setImage:current];
  289.     return self;
  290. }
  291.  
  292. - takeRepeatValueFrom:sender
  293. {
  294.     [self setRepeatValue:exp(12*[sender floatValue])-1];
  295.     return self;
  296. }
  297.  
  298.  
  299. ///
  300. ///    Menu generation
  301. /// 
  302. - setMenu:aMenuCell
  303. {
  304.     menu = [aMenuCell target];
  305.     [self updateMenu];
  306.     return self;
  307. }
  308.  
  309. - updateMenu
  310. {
  311.     id cell;
  312.     id matrix;
  313.     int i;
  314.     
  315.     if (!updateMenu) return self;
  316.     matrix = [menu itemList];
  317.     while([matrix cellCount]) [matrix removeRowAt:0 andFree:YES];
  318.     [menu setItemList:matrix];
  319.     for (i=0; i<imageCount; i++) {
  320.     cell = [menu addItem:imageNames[i] action:@selector(select:) keyEquivalent:0];
  321.     [cell setTarget:self];
  322.     }
  323.     [menu display];
  324.     return self;
  325. }
  326. //
  327. //    private:
  328. //
  329. - (int)getImage:(const char *)aName
  330. {
  331.     int i;
  332.     
  333.     if (aName==NULL) return -1;
  334.     for (i=0; i<imageCount; i++) if (strcmp(aName, imageNames[i])==0) break;
  335.     if (i>=imageCount) {
  336.     if (++imageCount>max) {
  337.         if (!max) {
  338.         imageNames = NX_ZONEMALLOC([self zone], imageNames, char *, 1);
  339.         imageTimes = NX_ZONEMALLOC([self zone], imageTimes, time_t, 1);
  340.         images = NX_ZONEMALLOC([self zone], images, NXImage *, 1);
  341.         max = 1;
  342.         } else {
  343.         max *= 2;
  344.         imageNames = NX_ZONEREALLOC([self zone], imageNames, char *, max);
  345.         imageTimes = NX_ZONEREALLOC([self zone], imageTimes, time_t, max);
  346.         images = NX_ZONEREALLOC([self zone], images, NXImage *, max);
  347.         }
  348.     }
  349.     imageNames[i]=NXCopyStringBufferFromZone(aName, [self zone]);
  350.     images[i] = nil;
  351.     }
  352.     return i;
  353. }
  354.  
  355. - setImage:(int)i
  356. {
  357.     struct stat sb;
  358.     char *p;
  359.     int flag;
  360.     
  361.     if (i>=0 && i<imageCount) {
  362.     if (imageNames[i][0]=='*') p=imageNames[i]+1; else p=imageNames[i];
  363.     flag = stat(p, &sb);
  364.     if (!images[i] || (flag==0 && imageTimes[i]<sb.st_mtime)) {
  365.         images[i]=[[NXImage allocFromZone:[self zone]] initFromFile:p];
  366.         imageTimes[i]=sb.st_mtime;
  367.         if (imageNames[i][0]=='*') [self resizeImage:i];
  368.     }
  369.     current = i;
  370.     }
  371.     [self updateMenu];
  372.     [self display];
  373.     return self;
  374. }
  375.  
  376. - resizeImage:(int)i
  377. {
  378.     const NXScreen *screen;
  379.     NXSize size;
  380.  
  381.     if (i>=0 && i<imageCount && images[i]) {
  382.     screen = [window screen];
  383.     size = screen->screenBounds.size;
  384.     [images[i] setScalable:YES];
  385.     [images[i] setSize:&size];
  386.     }
  387.     return self;
  388. }
  389.  
  390. //
  391. //    read and write defaults
  392. //
  393. - readDefault
  394. {
  395.     char p[256], f[256];
  396.     NXStream *s;
  397.         FILE *temp;
  398.     int ret;
  399.    
  400.  //    pictures==NXReadDefault( "Background", "Image");
  401.     if (s=NXMapFile(defaultfile, NX_READONLY)) {
  402.     while (NXScanf(s, " %255[^     \n=]%1[     \n]", p, f)==2) [self loadImageNamed:p];
  403.     ret = 1;
  404.     while (ret && (ret=NXScanf(s," = \"%255[^\n\"]\" ", f))!=EOF) {
  405.  //        printf("Default read: %s = %s.\n", p, f);
  406.         if (strncmp(p, "rep", 3)==0) [self setRepeatValue:atof(f)];
  407.         else printf("Illegal default in %s: %s=%s.\n", defaultfile, p, f);
  408.         ret=NXScanf(s," %255[^=\n] ", p);
  409.     }
  410.     NXCloseMemory(s, NX_FREEBUFFER);
  411.     [self setImage:0];
  412.     } else {
  413.         fprintf(stderr, "Could not read from %s - creating it.\n", defaultfile);
  414.                 temp = fopen(defaultfile, "w");
  415.                 fclose(temp);
  416.     }
  417.     return self;
  418. }
  419.  
  420. - writeDefault
  421. {
  422.     int i;
  423.     NXStream *s;
  424.     
  425.     s = NXOpenMemory(NULL, 0, NX_WRITEONLY) ;
  426.     for (i=0; i<imageCount; i++) NXPrintf(s,"%s ",imageNames[i]);
  427.     NXPrintf(s, " \nrepeat=\"%g\"\n", repeat);
  428.     if (NXSaveToFile(s, defaultfile)<0) {
  429.         printf("Could not write to %s.\n", defaultfile);
  430.     exit(1);
  431.     }
  432.     NXCloseMemory(s, NX_FREEBUFFER);
  433.  //    NXWriteDefault( "Background", "Image", p);  // Crashes default database
  434.     return self;
  435. }
  436.  
  437. //
  438. - mouseDown:(NXEvent *)event
  439. {
  440.     PSsetwindowlevel( -1, [window windowNum]);
  441.     [window orderWindow:NX_ABOVE relativeTo:0];
  442.     [window removeFromEventMask:NX_MOUSEDOWNMASK];
  443.     return self;
  444. }
  445.  
  446. - (BOOL)acceptsFirstMouse
  447. {
  448.     return YES;
  449. }
  450.  
  451. - drawSelf:(NXRect *)r :(int)count
  452. {
  453.     PSsetgray( NX_DKGRAY);
  454.     NXRectFill( &bounds);
  455.     if (permanent) { printf("Making permanent.\n"); PSputback(); }
  456.     if(imageCount) {
  457.     int i;
  458.     NXSize s;
  459.     NXSize screenSize;
  460.     NXPoint p={ 0, 0};
  461.     NXRect r={ p};
  462.     
  463.     [NXApp getScreenSize:&screenSize];
  464.     [images[current] getSize:&s];
  465.     r.size=s;
  466.  //    printf("Drawing image %s: [%g,%g].\n",imageNames[current],s.width,s.height);
  467.     if (s.width>0 && s.height>0) {
  468.         [images[current] composite:NX_COPY toPoint:&p];
  469.         for( i=s.width; i<screenSize.width; i+=s.width) {
  470.         p.x=i;
  471.         PSsplat( &r, &p);
  472.         }
  473.         p.x=0;
  474.         r.size.width=screenSize.width;
  475.         for( i=s.height; i<screenSize.height; i+=s.height) {
  476.         p.y=i;
  477.         PSsplat( &r, &p);
  478.         }
  479.     }
  480.     }
  481.     return self;
  482. }
  483. //
  484. - windowDidBecomeKey:sender
  485. {
  486.     PSsetwindowlevel( NX_DOCKLEVEL+1, [sender windowNum]);
  487.     return self;
  488. }
  489.  
  490. @end
  491.